昨天談了如何撰寫完美的 Task 文件,但再完美的規劃,如果不能正確執行,也只是紙上談兵。
今天要分享的是我在一人公司中最重要的發現。
開發不只是寫程式,更是確保「想法、規劃、實作、文件」四者的一致性。
在一人公司中,我既是規劃者,也是執行者。這種雙重身份容易產生一個問題:
早上的我:「這個功能應該這樣做!」(寫下完美規劃)
下午的我:「算了,這樣比較快...」(偏離原始設計)
晚上的我:「我剛剛做了什麼?」(忘記更新文件)
這就是為什麼我需要一套嚴謹的執行流程。
# 找到要執行的任務
$ ls docs/tasks/ | grep "developing"
0006_fr_database_migration_system.md # 開發中
# 仔細閱讀任務文件
$ cat docs/tasks/0006_fr_database_migration_system.md
關鍵檢查點:理解背景和動機(Why)、明確技術方案(How)、清楚驗收標準(What)、了解測試要求(Test)。
## 狀態
開發中 # 從規劃中改為開發中
## 更新歷程
- 2025-01-11:建立需求文件
- 2025-01-19:開始實作 # 新增今天日期
同時更新 docs/tasks/README.md
:
### 開發中
| 編號 | 任務名稱 | 類型 | 開始日期 | 負責人 | 進度 |
|------|----------|------|----------|---------|------|
| 0006 | 資料庫 Migration 系統 | FR | 2025-01-19 | Sam | 0% |
# 確保在正確的分支
git checkout -b feature/0006-database-migration
# 確認專案能正常建置
./gradlew clean build --no-daemon
# 執行現有測試確保基準正確
./gradlew allTests
這時候,我會切換到一個特殊的角色:Technical Implementation Architect (TIA)。
TIA (Technical Implementation Architect) 是我定義的一個 AI 協作角色,專門負責確保技術計劃與實際實作的一致性。
想像一下,你規劃要用 SQLDelight 2.0,但專案實際用的是 2.1。你計劃把檔案放在 migrations/ 資料夾,但實際路徑應該是 shared/src/commonMain/sqldelight/migrations/。這些差異如果不及早發現,會導致實作時不斷碰壁。
TIA 就像是一個嚴謹的技術顧問,在你開始寫程式碼前,先幫你檢查計劃是否可行、與現實是否相符。
在開始寫程式碼前,TIA 會審查任務文件:
## TIA Review Report - Pre-Implementation
### Summary
- Task: 0006_fr_database_migration_system.md
- Review Date: 2025-01-19
- Status: 需要調整
### Identified Issues
1. **SQLDelight 版本差異**
- Plan States: SQLDelight 2.0.0
- Actual State: SQLDelight 2.1.0 (libs.versions.toml)
- Correction: 更新文件使用 2.1.0 API
- Impact: API 略有不同,需調整實作方式
2. **Migration 檔案位置**
- Plan States: `migrations/`
- Actual State: 需要完整路徑 `shared/src/commonMain/sqldelight/migrations/`
- Correction: 更新文件路徑
- Impact: 避免建錯位置
根據 TIA 的審查結果,開始實作:
// 1. 建立 MigrationHelper.kt
// 位置:shared/src/commonMain/kotlin/.../data/migration/
class MigrationHelper(private val databaseDriverFactory: DatabaseDriverFactory) {
suspend fun initDatabase(): GrimoDatabase {
val driver = databaseDriverFactory.createDriver()
// TIA 提醒:SQLDelight 2.1.0 使用 awaitCreate 而非 await
val currentVersion = getVersion(driver)
if (currentVersion == 0L) {
GrimoDatabase.Schema.awaitCreate(driver)
} else if (currentVersion < GrimoDatabase.Schema.version) {
GrimoDatabase.Schema.awaitMigrate(
driver,
currentVersion,
GrimoDatabase.Schema.version
)
}
return GrimoDatabase(driver)
}
}
每完成一個重要步驟,立即更新:
## 進度追蹤
- [x] 建立 MigrationHelper 類別
- [x] 實作版本檢查邏輯
- [ ] 撰寫 migration 檔案
- [ ] 整合到 DatabaseModule
- [ ] 撰寫單元測試
# 更新資料庫設計文件
vim docs/architecture/database/migration-system.md
# 更新 CLAUDE.md 加入新的最佳實踐
vim CLAUDE.md
完成初版後,TIA 再次介入:
## TIA Review Report - Implementation Validation
### Verified Components
- MigrationHelper 正確實作
- Migration 檔案格式正確
- 版本管理邏輯無誤
### 發現的問題
1. **缺少錯誤處理**
- 問題:Migration 失敗時沒有 rollback
- 建議:加入 try-catch 和錯誤日誌
2. **測試覆蓋不足**
- 問題:只測試了 happy path
- 建議:加入失敗場景測試
### 需要的文件更新
- [ ] 更新 developer-guide.md 加入 migration 流程
- [ ] 在 CLAUDE.md 加入 migration 檔案命名規範
- [ ] 更新 database_schema.md 記錄版本歷史
根據 TIA 的建議進行改進:
// 加入錯誤處理
class MigrationHelper(
private val databaseDriverFactory: DatabaseDriverFactory,
private val logger: Logger = createLogger<MigrationHelper>()
) {
suspend fun initDatabase(): Result<GrimoDatabase> = runCatching {
val driver = databaseDriverFactory.createDriver()
try {
// Migration 邏輯
performMigration(driver)
Result.success(GrimoDatabase(driver))
} catch (e: Exception) {
logger.error(e) { "Migration failed" }
// 嘗試 rollback
driver.close()
Result.failure(e)
}
}
}
回到原始 Task 文件的驗收標準。
功能性需求全部通過:新安裝能自動建立資料庫、舊版本能自動升級、Migration 失敗能 rollback、支援跳版本升級。
非功能性需求也大部分完成:Migration 執行時間實測只要 1.2 秒,錯誤訊息清楚明確,單元測試覆蓋率達到 85%。只剩文件更新還在進行中。
測試案例全部通過:Test_FirstInstall、Test_UpgradeV1toV3、Test_MigrationFailure、Test_DataIntegrity 都 PASSED。
## 完成任務:知識沉澱
### 1. 更新 Task 文件的「實作解決方案」
```markdown
## 實作解決方案
### 實際實作要點
1. **使用 SQLDelight 2.1.0 新 API**
- awaitCreate() 取代 await()
- 更簡潔的非同步處理
2. **錯誤處理策略**
- 使用 Kotlin Result 類型
- 失敗時自動關閉 driver
- 完整的錯誤日誌
3. **測試策略**
- 使用 in-memory 資料庫測試
- 模擬各種 migration 場景
- 驗證資料完整性
### 踩過的坑
1. **問題**:Migration 檔案命名必須是純數字
**解決**:使用 1.sqm, 2.sqm 而非 v1.sqm
2. **問題**:測試時 migration 不執行
**解決**:測試需要明確呼叫 migrate
### 效能優化
- Migration 使用 transaction 包裹
- 批次處理大量資料更新
- 適當的索引策略
提交前的文件檢查清單包括:Task 文件狀態改為「已完成」、docs/tasks/README.md 更新任務狀態、CLAUDE.md 加入新的開發規範、database_schema.md 更新 schema 版本、developer-guide.md 加入 migration 指南、更新 CHANGELOG.md。
開發 30 分鐘 → 更新文件 5 分鐘 → 繼續開發
#!/bin/bash
# .git/hooks/pre-commit
# 檢查是否有未更新的文件
if git diff --cached --name-only | grep -q "^src/"; then
echo "記得更新相關文件:"
echo " - Task 文件進度"
echo " - CLAUDE.md(如有新規範)"
echo " - 相關設計文件"
fi
寫文件 → 寫測試 → 寫程式碼 → 更新文件
在一人公司中,你既是規劃者也是執行者。這很容易產生「當局者迷」的問題。你寫的計劃可能基於過時的記憶,或是理想化的假設。
TIA 角色的工作流程是這樣的:
引入 TIA 角色後,我的開發品質顯著提升。
以前沒有 TIA 時,經常偏離原始設計,文件與程式碼脫節,重複踩相同的坑,技術債務不斷累積。
有了 TIA 之後,計劃與實作高度一致,文件始終保持更新,問題提前被發現,技術債務受到控制。
效果很明顯。計劃準確度大幅提升,Bug 率顯著降低,文件更新率達到 100%(因為強制檢查),重做時間大幅減少。
#!/bin/bash
# check-task.sh
TASK_FILE=$1
echo "Task Execution Checklist"
echo "=========================="
# 檢查必要章節
grep -q "## 實作解決方案" $TASK_FILE || echo "Missing: 實作解決方案"
grep -q "已完成" $TASK_FILE && echo "Status: Completed"
# 檢查相關文件
echo "Related Documents:"
grep -o "docs/[^)]*" $TASK_FILE | sort -u
# 生成進度報告
echo "## Task Progress Report"
echo "Date: $(date +%Y-%m-%d)"
echo ""
echo "### Status Overview"
grep "## 狀態" docs/tasks/*.md |
cut -d: -f2 | sort | uniq -c
解法:使用不同的 Git 使用者
# 作為開發者
git config user.name "Developer"
# 作為 TIA 審查
git config user.name "TIA Reviewer"
解法:讓 AI 扮演 TIA
我:請以 TIA 角色審查我的實作,確認與專案實際狀況的一致性
Claude:我會檢查:
1. 版本是否相符(libs.versions.toml vs 計劃)
2. 檔案路徑是否正確
3. API 名稱是否一致
4. 資料庫 schema 是否匹配
[產出審查報告]
解法:建立 Checklist 模板
## Commit Checklist
- [ ] Code 完成
- [ ] Test 通過
- [ ] Task 文件更新
- [ ] 相關文件同步
- [ ] CLAUDE.md 檢查
成功執行任務的關鍵不是技術能力。
而是紀律,嚴格遵循流程,不走捷徑。而是工具,TIA 角色、檢查腳本、自動化。而是流程,清晰的步驟、即時的文件更新。
對一人公司來說,這種「自我管理」的能力特別重要。你是自己的 PM、開發者、測試員、文件管理員。沒有外部監督,全靠自律。好的流程讓你不需要依賴記憶。TIA 角色幫你保持客觀。
優秀的執行不是完美的程式碼,而是可追溯、可維護、可演進的系統。
「程式碼是暫時的,但決策和知識是永恆的。」
關於作者:Sam,一人公司創辦人。正在打造 Grimo,一個智能任務管理和分配平台。
專案連結:GitHub - grimostudio